package handler

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"server/framework/web/context"
	"server/framework/web/middleware"
	"sort"
	"strings"
)

type Tree struct {
	tree map[string]*Node
}

// ServerHttp 路由查找，handleFunc调用
func (t *Tree) ServeHTTP(c *context.Context) {
	pattern := c.R.URL.Path
	method := c.R.Method
	node := t.tree[method]

	// 快路径
	if pattern == "/" {
		if node.handleFunc != nil {
			node.handleFunc(c)
		} else {
			c.RespNotFound()
			return
		}
		return
	}

	// 慢路径
	pathSlice, err := t.handlePattern(pattern)
	if err != nil {
		log.Println("handle pattern error:", err)
		return
	}

	for i, pathItem := range pathSlice {
		if node.nodeType == nodeTypeAny {
			node.Match(c, pattern[i:]) // 动态路径添加至c.RouteDynamic
			break
		}
		cNode, ok := t.findMatchChild(c, node, pathItem)
		if !ok {
			c.RespNotFound()
			return
		}
		node = cNode
	}
	if node.handleFunc != nil {
		node.handleFunc(c)
	} else {
		c.RespNotFound()
		return
	}
}

func (t *Tree) findMatchChild(c *context.Context, node *Node, pattern string) (*Node, bool) {
	candidates := make([]*Node, 0)
	for _, child := range node.children {
		if child.Match(c, pattern) {
			candidates = append(candidates, child)
		}
	}
	if len(candidates) == 0 {
		return nil, false
	}

	sort.Slice(candidates, func(i, j int) bool {
		return candidates[i].nodeType < candidates[j].nodeType
	})

	return candidates[0], true
}

func (t *Tree) createNode(path string) *Node {
	var cNode *Node
	if path == "*" {
		cNode = NewAnyNode(path)
	} else if path[0] == ':' {
		cNode = NewParamNode(path[1:])
	} else if path[0] == '(' && path[len(path)-1] == ')' {
		cNode = NewRegNode(path)
	} else {
		cNode = NewStaticNode(path)
	}

	return cNode
}

func (t *Tree) addChildNodes(node *Node, pathSlice []string, handleFunc middleware.HandleFunc) {
	for _, pathItem := range pathSlice {
		if node.children == nil {
			node.children = make([]*Node, 0)
		}
		cNode := t.createNode(pathItem)
		node.children = append(node.children, cNode)
		node = cNode
	}
	if node.handleFunc != nil {
		_ = fmt.Errorf("重复注册，已注册路由：%s", node.path)
		return
	}
	node.handleFunc = handleFunc
}

// Route 路由注册
func (t *Tree) Route(method string, pattern string, handleFunc middleware.HandleFunc) {
	node := t.tree[method]

	// 快路径
	if pattern == "/" {
		if node.handleFunc != nil {
			_ = fmt.Errorf("重复注册，已注册路由：%s", node.path)
			return
		}
		node.handleFunc = handleFunc
		return
	}

	// 慢路径
	pathSlice, err := t.handlePattern(pattern)
	if err != nil {
		log.Println("handle pattern error:", err)
		return
	}

	// 路由不存在 =》 创建子节点
	// 路由存在 =》 绑定handleFunc
	for i, pathItem := range pathSlice {
		cNode, ok := t.findMatchChild(nil, node, pathItem)
		if !ok {
			t.addChildNodes(node, pathSlice[i:], handleFunc)
			return
		}
		node = cNode
	}
	if node.handleFunc != nil {
		_ = fmt.Errorf("重复注册，已注册路由：%s", node.path)
		return
	}
	node.handleFunc = handleFunc
}

// nodeTypeAny、nodeTypeParam、nodeTypeReg必须在叶子结点
// 非法路由示例： /a/*/d /a/:id/* /a/`[0-9]`/*
// 说明：/a/* 不匹配/a，仅匹配/a所有孩子节点
func (t *Tree) handlePattern(pattern string) ([]string, error) {
	pattern = strings.Trim(pattern, "/") // 移除两侧"/"
	pathSlice := strings.Split(pattern, "/")

	// 慢路径
	for i, path := range pathSlice {
		isLeaf := i == len(pathSlice)-1
		if path == "*" && !isLeaf {
			return nil, errors.New("pattern must end with *")
		} else if path[0] == ':' && !isLeaf {
			return nil, errors.New("pattern must end with param_route")
		} else if path[0] == '(' && path[len(path)-1] == ')' && !isLeaf {
			return nil, errors.New("pattern must end with reg_route")
		}
	}

	return pathSlice, nil
}

var _ Handler = &Tree{}

func NewTree() *Tree {
	return &Tree{tree: map[string]*Node{
		http.MethodGet:    NewStaticNode(""),
		http.MethodPost:   NewStaticNode(""),
		http.MethodPut:    NewStaticNode(""),
		http.MethodPatch:  NewStaticNode(""),
		http.MethodDelete: NewStaticNode(""),
	}}
}
